package dao

import (
	"errors"
	"fitness/internal/entity"
	"fitness/internal/entity/system"
	"fitness/pkg/utils"
	"github.com/duke-git/lancet/v2/convertor"
	"go.uber.org/zap"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
	"strconv"
	"strings"
	"time"
)

type SysUserDao struct {
	DB             *gorm.DB
	SysUserRoleDao *SysUserRolesDao
	Logger         *zap.Logger
}

func NewSysUserDao(db *gorm.DB, sysUserRoleDao *SysUserRolesDao, logger *zap.Logger) *SysUserDao {
	return &SysUserDao{
		DB:             db,
		SysUserRoleDao: sysUserRoleDao,
		Logger:         logger,
	}
}
func (sysUserDao *SysUserDao) getGDB() *gorm.DB {
	return sysUserDao.DB
}

// ListPagedUsers 列表查询
func (sysUserDao *SysUserDao) ListPagedUsers(queryParams system.SysUserPageQuery) (utils.Page[system.UserPageVO], error) {
	sql := `SELECT u.id,
				   u.username,
				   u.nickname,
				   u.mobile,
					u.gender,
					u.avatar,
					u.status,
					d.NAME AS dept_name,
           GROUP_CONCAT( r.NAME ) AS role_names,
           u.create_time`
	where := ` FROM
			sys_user u
			LEFT JOIN sys_dept d ON u.dept_id = d.id
			LEFT JOIN sys_user_role sur ON u.id = sur.user_id
			LEFT JOIN sys_role r ON sur.role_id = r.id where u.is_deleted = 0 AND u.username != 'root'`

	if queryParams.PageQuery.Keywords != nil && *queryParams.PageQuery.Keywords != "" {
		where = where + ` and (
		           u.username LIKE '%` + *queryParams.PageQuery.Keywords + `%'
		           OR u.nickname LIKE '%` + *queryParams.PageQuery.Keywords + `%'
		           OR u.mobile LIKE '%` + *queryParams.PageQuery.Keywords + `%'
					OR u.id ='` + *queryParams.PageQuery.Keywords + `'
		           )`
	}

	if queryParams.Status != nil {
		status := ` AND u.status = ` + convertor.ToString(*queryParams.Status)
		where = where + status
	}
	if queryParams.DeptId != nil {
		dept := ` AND concat(',',concat(d.tree_path,',',d.id),',') like ` + `'%` +
			strconv.FormatUint(*queryParams.DeptId, 10) + `%'`
		where = where + dept
	}
	if queryParams.StartTime != nil {
		startTime := ` AND u.create_time > '` + *queryParams.StartTime + `'`
		where = where + startTime
	}
	if queryParams.EndTime != nil {
		endTime := ` AND u.create_time < '` + *queryParams.EndTime + `'`
		where = where + endTime
	}
	if where != "" {
		where = where + ` GROUP BY u.id`
	} else {
		where = where + ` GROUP BY u.id`
	}

	var totalRecords int64
	page := *queryParams.PageQuery.PageNum      // 当前页码
	pageSize := *queryParams.PageQuery.PageSize // 每页数据量

	// 计算偏移量
	offset := (page - 1) * pageSize
	var users = make([]system.UserBO, 0)

	var res utils.Page[system.UserPageVO]

	err := sysUserDao.getGDB().Raw(sql + where).Offset(int(offset)).Limit(int(pageSize)).Find(&users).Error
	if err != nil {
		return res, err
	}
	// 获取总记录数
	countSql := "select count(1)  from ( select u.id " + where + ") as t"
	err = sysUserDao.getGDB().Raw(countSql).Count(&totalRecords).Error
	if err != nil {
		return res, err
	}
	//总数量
	res.Total = totalRecords
	var userVos []system.UserPageVO
	for _, bo := range users {
		var vo system.UserPageVO
		vo.ID = bo.ID
		vo.UserName = bo.UserName
		vo.NickName = bo.NickName
		vo.Mobile = bo.Mobile
		vo.Gender = bo.Gender
		vo.Avatar = bo.Avatar
		vo.Email = bo.Email
		vo.Status = bo.Status
		vo.DeptName = bo.DeptName
		vo.RoleNames = bo.RoleNames
		vo.UserType = bo.UserType
		if !bo.CreateTime.IsZero() {
			vo.CreateTime = bo.CreateTime.Format("2006-01-02 15:04:05")
		} else {
			vo.CreateTime = ""
		}
		userVos = append(userVos, vo)
	}
	res.List = userVos
	return res, nil
}

// 修改用户的密码
func (sysUserDao *SysUserDao) UpdatePassword(userId int, password string) (bool, error) {
	// 生成密码的哈希值
	// 第二个参数是成本参数，其值可以是4到31之间的任何整数，默认值是10
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return false, err
	}
	s0 := string(hashedPassword)
	sysUser := system.SysUser{
		Password: &s0,
	}
	err = sysUserDao.getGDB().Where("id = ?", userId).Updates(&sysUser).Error
	if err != nil {
		return false, err
	}
	return true, nil
}

// 根据id获取用户信息
func (sysUserDao *SysUserDao) GetUserForm(id uint64) (system.UserForm, error) {
	var user system.SysUser
	err := sysUserDao.getGDB().Model(system.SysUser{}).Where("id = ? and is_deleted = 0", id).First(&user).Error
	var userForm system.UserForm
	if err != nil {
		sysUserDao.Logger.Error("查询用户信息报错", zap.Error(err))
		return userForm, err
	}
	userForm = system.UserForm{
		ID:       user.ID,
		UserName: user.UserName,
		NickName: user.NickName,
		Mobile:   user.Mobile,
		Gender:   user.Gender,
		Avatar:   user.Avatar,
		Email:    user.Email,
		Status:   user.Status,
		DeptId:   user.DeptId,
	}
	userRoles := sysUserDao.SysUserRoleDao.FindRolesByUserId(*userForm.ID)
	var roleIds []*uint64
	for _, userRole := range userRoles {
		roleIds = append(roleIds, userRole.RoleId)
	}
	userForm.RoleIds = roleIds
	return userForm, nil
}

// 根据用户id查询
func (sysUserDao *SysUserDao) FindSysUserById(id uint64) (system.SysUser, error) {
	var sysUser system.SysUser
	if id == 0 {
		return sysUser, nil
	}
	err := sysUserDao.getGDB().Model(&system.SysUser{}).
		Where("id = ?", id).
		First(&sysUser).Error
	if err != nil {
		return sysUser, errors.New(err.Error())
	}
	return sysUser, nil
}

// FindSysUserByUserName 根据用户名称查询
func (sysUserDao *SysUserDao) FindSysUserByUserName(username string) (system.SysUser, error) {
	var sysUser system.SysUser
	sysUserDao.getGDB().Model(&system.SysUser{}).
		Where("is_deleted = '0' and username = ?", username).
		First(&sysUser)
	return sysUser, nil
}

// 获取所有用户
func (sysUserDao *SysUserDao) FindUsers() ([]system.SysUser, error) {
	var sysUsers []system.SysUser
	err := sysUserDao.getGDB().Model(&system.SysUser{}).Find(&sysUsers).Error
	if err != nil {
		return sysUsers, err
	}
	return sysUsers, nil
}

// 保存用户
func (sysUserDao *SysUserDao) SaveUser(userForm system.UserForm) (userId uint64, err error) {
	err = sysUserDao.getGDB().Transaction(func(tx *gorm.DB) error {
		userId, err = sysUserDao.SaveUserWithDB(tx, userForm)
		if err != nil {
			return err
		}
		return nil
	})
	return userId, err
}

// 保存用户 事务
func (sysUserDao *SysUserDao) SaveUserWithDB(tx *gorm.DB, userForm system.UserForm) (uint64, error) {
	var userId uint64
	userId = 0
	username := userForm.UserName
	var count int64
	tx.Model(&system.SysUser{}).Where("username = ?  ", username).Count(&count)
	if count > 0 {
		return userId, errors.New("用户名已存在")
	}
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte("123456"), bcrypt.DefaultCost)
	if err != nil {
		sysUserDao.Logger.Error("密码设置错误", zap.Error(err))
		return userId, errors.New("密码设置错误")
	}
	deleted := uint8(0)
	s := string(hashedPassword)
	var sysUser = system.SysUser{
		Model: entity.Model{
			CreateTime: time.Now(),
			IsDeleted:  &deleted,
		},
		UserName: userForm.UserName,
		NickName: userForm.NickName,
		Gender:   userForm.Gender,
		Password: &s,
		DeptId:   userForm.DeptId,
		Avatar:   userForm.Avatar,
		Mobile:   userForm.Mobile,
		Status:   userForm.Status,
		Email:    userForm.Email,
	}
	// 新增用户
	err = tx.Model(&system.SysUser{}).Save(&sysUser).Error
	userId = *sysUser.ID
	if err == nil {
		// 保存用户角色
		err := sysUserDao.SysUserRoleDao.saveUserRoles(tx, sysUser.ID, userForm.RoleIds)
		if err != nil {
			return userId, err
		}
		return userId, nil
	} else {
		sysUserDao.Logger.Error("保存新用户失败", zap.Error(err))
		return userId, errors.New("保存新用户失败")
	}
}

// 修改用户
func (sysUserDao *SysUserDao) UpdateUser(userForm system.UserForm) (b bool, err error) {
	err = sysUserDao.getGDB().Transaction(func(tx *gorm.DB) error {
		username := userForm.UserName
		var count int64
		tx.Model(&system.SysUser{}).Where("username = ? and id <> ? ",
			username, userForm.ID).Count(&count)
		if count > 0 {
			b = false
			err = errors.New("用户名已存在")
			return err
		}
		deleted := uint8(0)
		var sysUser = system.SysUser{
			Model: entity.Model{
				ID:         userForm.ID,
				UpdateTime: time.Now(),
				IsDeleted:  &deleted,
			},
			UserName: userForm.UserName,
			NickName: userForm.NickName,
			Gender:   userForm.Gender,
			DeptId:   userForm.DeptId,
			Avatar:   userForm.Avatar,
			Mobile:   userForm.Mobile,
			Status:   userForm.Status,
			Email:    userForm.Email,
		}
		// 修改用户
		err = sysUserDao.getGDB().Model(&system.SysUser{}).Where("id = ? ", sysUser.ID).
			Update("status", userForm.Status).Updates(&sysUser).Error
		if err == nil {
			// 保存用户角色
			err := sysUserDao.SysUserRoleDao.saveUserRoles(tx, sysUser.ID, userForm.RoleIds)
			return err
		} else {
			b = false
			err = errors.New("修改用户失败")
			return err
		}
	})
	if err != nil {
		return false, err
	}
	return true, nil
}

// 删除用户
func (sysUserDao *SysUserDao) DeleteUsers(ids string) (bool, error) {
	if ids == "" {
		return false, errors.New("至少需要一个参数")
	}
	split := strings.Split(ids, ",")

	err := sysUserDao.getGDB().Transaction(func(tx *gorm.DB) error {
		var list []uint64
		for _, val := range split {
			end, _ := strconv.ParseUint(val, 10, 64)
			list = append(list, end)
		}
		err := sysUserDao.getGDB().Delete(&system.SysUser{}, list).Error
		return err
	})
	if err != nil {
		return false, err
	} else {
		return true, nil
	}
}

func (sysUserDao *SysUserDao) Option(userTypeUint *uint64) ([]system.UserOption, error) {
	var options []system.UserOption
	tx := sysUserDao.getGDB().Model(&system.SysUser{}).
		Select("id,username").
		Where("is_deleted = 0")
	if userTypeUint != nil {
		tx.Where("user_type = ?", *userTypeUint)
	}
	err := tx.Find(&options).Error
	if err != nil {
		return options, err
	}
	return options, nil
}

// 修改客服的昵称
func (sysUserDao *SysUserDao) UpdateProfile(id uint64, nickname string) (bool, error) {
	err := sysUserDao.getGDB().Transaction(func(tx *gorm.DB) error {
		err := sysUserDao.getGDB().Model(&system.SysUser{}).Where("id = ? ", id).
			Update("nickname", nickname).Error
		return err
	})
	if err != nil {
		return false, err
	}
	return true, nil
}

// 修改用户头像
func (sysUserDao *SysUserDao) UpdateAvatar(id uint64, filepath string) (bool, error) {
	err := sysUserDao.getGDB().Transaction(func(tx *gorm.DB) error {
		err := sysUserDao.getGDB().Model(&system.SysUser{}).Where("id = ? ", id).
			Update("avatar", filepath).Error
		return err
	})
	if err != nil {
		return false, err
	}
	return true, nil
}
